package com.tx.admin.runner;

import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.tx.admin.annotation.Rbac;
import com.tx.admin.annotation.RbacMapping;
import com.tx.admin.controller.SuperController;
import com.tx.admin.entity.rbac.DataFunctionEntity;
import com.tx.admin.entity.rbac.DataPermissionEntity;
import com.tx.admin.entity.rbac.DataPermissionEntity.DataScope;
import com.tx.admin.entity.rbac.DepartmentEntity;
import com.tx.admin.entity.rbac.RoleEntity;
import com.tx.admin.entity.rbac.UserEntity;
import com.tx.admin.service.rbac.DataFunctionService;
import com.tx.admin.service.rbac.DataPermissionService;
import com.tx.admin.service.rbac.DepartmentService;
import com.tx.admin.service.rbac.RoleService;
import com.tx.admin.service.rbac.UserService;

@Component
@Order(value = 1)
public class ApplicationRunner implements CommandLineRunner {

	@Autowired
	private DepartmentService departmentService;
	@Autowired
	private DataPermissionService dataPermissionService;
	@Autowired
	private DataFunctionService dataFunctionService;
	@Autowired
	private RoleService roleService;
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private List<SuperController> controllers;
	
	private DepartmentEntity initDeparment() {
		DepartmentEntity e = new DepartmentEntity();
		e.setLabel("根部门");
		e.setParentId("0");
		this.departmentService.save(e);
		return e;
	}
	
	private RoleEntity initRole() {
	
		StringBuffer df = new StringBuffer(),
			dp = new StringBuffer();
		this.initDataFunction().forEach(val -> {
			df.append(val.getId()+",")	;
		});
		this.initDataPermisson().forEach(val -> {
			if(StringUtils.isBlank(val.getDataScope())) {
				return;
			}
			dp.append(val.getId()+",")	;
		});
		RoleEntity role = new RoleEntity();
		role.setTitle("超级角色");
		role.setDataFunctionIds(df.toString());
		role.setDataPermissionIds(dp.toString());
		this.roleService.save(role);
		return role;
	}
	
	private UserEntity initUser() {
		RoleEntity role = this.initRole();
		DepartmentEntity department = this.initDeparment();
		UserEntity user = new UserEntity();
		user.setUserName("super_admin");
		user.setPassword("super_admin");
		user.setRoleIds(role.getId());
		user.setDepartmentId(department.getId());
		this.userService.save(user);
		return user;
	}
	
	
	
	private List<DataFunctionEntity> initDataFunction() {
		List<DataFunctionEntity> list = new LinkedList<>();
		controllers.parallelStream().forEach(val -> {
			Class<?> clazz = val.getClass();
			Rbac rbac = AnnotationUtils.findAnnotation(clazz, Rbac.class);
			if(rbac == null) {
				return;
			}else if(!rbac.dataFunciton()) {
				return;
			}
			DataFunctionEntity parent = new DataFunctionEntity();
			parent.init();
			parent.setLabel(rbac.value());
			parent.setId(rbac.value());
			list.add(parent);
			for(Method method:clazz.getDeclaredMethods()) {
				RbacMapping rbacMapping = AnnotationUtils.findAnnotation(method, RbacMapping.class);
				if(rbacMapping == null) {
					continue;
				}
				DataFunctionEntity children = new DataFunctionEntity();
				children.setParentId(parent.getId());
				children.setLabel(rbacMapping.value());
				children.setId(parent.getId()+"-"+rbacMapping.value());
				children.init();
				list.add(children);
			}
		});
		
		this.dataFunctionService.save(list);
		return list;
	}
	
	private List<DataPermissionEntity> initDataPermisson() {
		List<DataPermissionEntity> list = new LinkedList<>();
		controllers.parallelStream().forEach(val -> {
			Class<?> clazz = val.getClass();
			Rbac rbac = AnnotationUtils.findAnnotation(clazz, Rbac.class);
			if(rbac == null) {
				return;
			}else if(!rbac.dataPermisson()) {
				return;
			}
			DataPermissionEntity parent = new DataPermissionEntity();
			parent.init();
			parent.setDataService(rbac.value());
			parent.setLabel(rbac.value());
			parent.setId(rbac.value());
			list.add(parent);
			for(Method method:clazz.getDeclaredMethods()) {
				RbacMapping rbacMapping = AnnotationUtils.findAnnotation(method, RbacMapping.class);
				if(rbacMapping == null) {
					continue;
				}else if(!rbacMapping.dataPermission()) {
					continue;
				}
				DataPermissionEntity children = new DataPermissionEntity();
				children.setId(parent.getId());
				children.setLabel(rbacMapping.value());
				children.setDataMethod(rbacMapping.value());
				children.setDataService(rbac.value());
				children.setLabel(rbacMapping.value());
				children.init();
				children.setId(parent.getId()+"-"+rbacMapping.value());
				list.add(children);
				for(DataScope dataScope:rbacMapping.dataScopes()) {
					DataPermissionEntity grandson = new DataPermissionEntity();
					grandson.setId(children.getId());
					grandson.setDataScope(dataScope.name());
					grandson.setLabel(rbacMapping.value());
					grandson.setDataMethod(rbacMapping.value());
					grandson.setDataService(rbac.value());
					grandson.setLabel(rbac.value());
					grandson.init();
					grandson.setId(children.getId()+"-"+dataScope.name());
					list.add(grandson);
				}
				
			}
		});
		
		this.dataPermissionService.save(list);
		return list;
	}
	
	@Override
	public void run(String... args) throws Exception {
		// TODO Auto-generated method stub
		if(this.userService.count() == 0) {
			this.initUser();
		}

	}

}
